package it.unipg.bipod.web;

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Vector;

import it.unipg.bipod.applicationLogic.*;
import it.unipg.bipod.dataModel.*;

/**
 * DocenteDocentiBean gestisce le attivita' della segreteria collegate alla gestione dei docenti.<br>
 * Permette di consultare l'elenco dei docenti con le relative richieste di assegnazione,
 * di modificare i dati dei docenti, di creare nuovi docenti o di registrarli a BiPoD.<br>
 * Sono presenti due sottoclassi pubbliche: DocenteBean e RichiestaBean.<br>
 * Eventuali messaggi o errori vengono segnalati mediante i metodi forniti da DefaultBean.
 * 
 * @author Lorenzo Porzi
 * @see DefaultBean
 * @see SegretarioBean
 */
public class SegretarioDocentiBean extends DefaultBean {
	private SegretarioApplication application;
	
	private DocenteBean[] docenti; // L'elenco dei docenti di BiPoD
	private DocenteBean docenteInDettaglio; // Il docente correntemente visualizzato nel dettaglio
	private DocenteBean nuovoDocente; // Il docente in fase di creazione
	private String nomeUtenteDaRegistrare; // Il nome utente del docente che si sta registrando al servizio
	
	private int paginaCorrente;
	
	/**
	 * Crea un nuovo SegretarioDocentiBean collegato ad una {@link SegretarioApplication}.<br>
	 * L'elenco dei docenti viene caricato immediatamente dal database.
	 * 
	 * @param application la {@link SegretarioApplication} da utilizzare con questo SegretarioDocentiBean.
	 */
	public SegretarioDocentiBean(SegretarioApplication application) {
		super();
		
		this.application = application;
		
		docenteInDettaglio = null;
		nuovoDocente = null;
		setNomeUtenteDaRegistrare("");
		
		paginaCorrente = 1;
		
		// Carica i docenti
		caricaDocenti();
	}
	
	public int getPaginaCorrente() {
		return paginaCorrente;
	}
	
	public void setPaginaCorrente(int paginaCorrente) {
		this.paginaCorrente = paginaCorrente;
	}
	
	public Vector<Integer> getPagine() {
		Vector<Integer> out = new Vector<Integer>();
		
		for (int i = 0; i < getNumeroPagine(); ++i)
			out.add(i + 1);
		
		return out;
	}
	
	/* --------------------------------
	 * Metodi per l'estrazione dei dati
	 * -------------------------------- */
	
	/**
	 * @return un array di {@link DocenteBean} con la pagina selezionata dell'elenco dei docenti.
	 */
	public DocenteBean[] getDocenti() {		
		if (paginaCorrente >= 1 && paginaCorrente <= getNumeroPagine())
			return getPagina(paginaCorrente); // Ritorna la pagina selezionata
		else
			return getPagina(1); // Ritorna la prima pagina
	}
	
	/**
	 * @return il numero di pagine di docenti.
	 */
	public int getNumeroPagine() {
		return (int)Math.ceil((double)docenti.length / PAGE_SIZE);
	}
	
	/**
	 * @return il numero di docenti presenti nell'elenco.
	 */
	public int getNumeroDocenti() {
		return docenti.length;
	}
	
	/* -------------------------------------------------
	 * Getters e setters per proprieta' e bean secondari
	 * ------------------------------------------------- */
	
	/**
	 * @return il DocenteBean del docente osservato in dettaglio.
	 */
	public DocenteBean getDocenteInDettaglio() {
		return docenteInDettaglio;
	}
	
	/**
	 * @return il DocenteBean del docente che si sta creando.
	 */
	public DocenteBean getNuovoDocente() {
		return nuovoDocente;
	}
	
	/**
	 * Imposta il nomeUtente del docente che si vuole registrare.
	 * 
	 * @param nomeUtenteDaRegistrare il nomeUtente del docente che si vuole registrare a BiPoD.
	 */
	public void setNomeUtenteDaRegistrare(String nomeUtenteDaRegistrare) {
		this.nomeUtenteDaRegistrare = nomeUtenteDaRegistrare;
	}

	/**
	 * @return il nomeUtente del docente che si vuole registrare a BiPoD.
	 */
	public String getNomeUtenteDaRegistrare() {
		return nomeUtenteDaRegistrare;
	}
	
	/* ---------------------
	 * Metodi di navigazione
	 * --------------------- */
	
	/**
	 * Imposta un nuovo DocenteBean nuovo come nuovoDocente e va alla pagina di creazione nuovo docente.
	 * 
	 * @return "/pages/segretario-docente-nuovo"
	 */
	public String goToCreaDocente() {
		nuovoDocente = new DocenteBean();
		
		return "/pages/segretario-docente-nuovo";
	}
	
	/**
	 * Registra a BiPoD un docente che possiede delle credenziali di accesso ai servizi web della facolta'.<br>
	 * Questo metodo utilizza le seguenti proprieta' di presentation.ini:
	 * <ul>
	 *   <li><b>msgDocenteRegistrato</b>: il messaggio visualizzato quando la registrazione riesce.</li>
	 *   <li><b>msgErroreDocenteNonPresente</b>: il messaggio visualizzato quando il nomeUtente fornito non corrisponde
	 *   a nessun utente.</li>
	 *   <li><b>msgErroreDocenteComeSegretario</b>: il messaggio visualizzato quando il nome utente fornito
	 *   corrisponde all'account di un segretario.</li>
	 *   <li><b>msgErroreDocenteRegistrato</b>: il messaggio visualizzato quando il nome utente corrisponde a quello
	 *   di un docente gia' registrato a BiPoD.</li>
	 *   <li><b>msgErroreRegistrazioneDocente</b>: il messaggio visualizzato quando la registrazione non riesce
	 *   a causa di errori sconosciuti.</li>
	 * </ul>
	 */
	public void registraDocente() {
		try {
			application.registraDocente(nomeUtenteDaRegistrare);
			
			addInfoMessage(getSettings().getProperty("msgDocenteRegistrato"));
		} catch (StatoDocenteException e) {
			switch (e.getStatoDocente()) {
			case StatoDocenteException.NON_PRESENTE:
				addWarnMessage(getSettings().getProperty("msgErroreDocenteNonPresente"));
				break;
			case StatoDocenteException.PRESENTE_COME_SEGRETARIO:
				addWarnMessage(getSettings().getProperty("msgErroreDocenteComeSegretario"));
				break;
			case StatoDocenteException.REGISTRATO:
				addWarnMessage(getSettings().getProperty("msgErroreDocenteRegistrato"));
			}
		} catch (ApplicationException e) {
			addWarnMessage(getSettings().getProperty("msgErroreRegistrazioneDocente"));
		}
	}
	
	/* ------------
	 * Altri metodi
	 * ------------ */

	/**
	 * @return ritorna un array di stringhe contenente "si" e "no", utilizzato per il menu' di selezione
	 * dello stato di attivazione del docente
	 */
	public String[] getOpzioniAttivazione() {
		String[] opzioni = {"si", "no"};
		
		return opzioni;
	}
	
	/**
	 * Carica la lista dei docenti dal database in una variabile locale.<br>
	 * Gli altri metodi che utilizzano la lista dei docenti accedono alla variabile locale
	 * invece che al database. Ogni metodo che causi aggiornamenti all'elenco dei docenti
	 * deve richiamare caricaDocenti() per aggiornare l'elenco conservato in memoria.
	 */
	private void caricaDocenti() {
		try {
			Docente[] docenti = application.getDocenti();
			this.docenti = new DocenteBean[docenti.length];
			for (int i = 0; i < docenti.length; ++i)
				this.docenti[i] = new DocenteBean(docenti[i]);
		} catch (ApplicationException e) {
			this.docenti = new DocenteBean[0];
		}
	}
	
	private DocenteBean[] getPagina(int pagina) {
		Vector<DocenteBean> outVector = new Vector<DocenteBean>(PAGE_SIZE);
		
		for (int i = (pagina - 1) * PAGE_SIZE; i < pagina * PAGE_SIZE && i < docenti.length; ++i)
			outVector.add(docenti[i]);
		
		DocenteBean[] out = new DocenteBean[outVector.size()];
		outVector.toArray(out);
		return out;
	}
	
	/**
	 * DocenteBean incapsula un docente e fornisce funzionalita' aggiuntive.<br>
	 * Permette di modificare i dati di un docente pre-esistente oppure di creare un docente nuovo.
	 * 
	 * @author Lorenzo Porzi
	 *
	 */
	public class DocenteBean {
		private Docente docente; // Il docente incapsulato
		private Docente docenteOld; // I dati iniziali del docente (variabile utilizzata per verificare l'effettiva modifica dei dati)
		private Registrazione registrazioneDocente; // La registrazione del docente
		private RichiestaBean[] richieste; // Le richieste effettuate dal docente
		
		private boolean inEliminazione = false;
		
		/**
		 * Crea un DocenteBean per un nuovo docente
		 */
		public DocenteBean() {			
			this.docente = new Docente();
			registrazioneDocente = new Registrazione();
		}
		
		/**
		 * Crea un DocenteBean associato ad un docente esistente.<br>
		 * L'elenco delle richieste viene caricato immediatamente.
		 * 
		 * @param docente il docente da associare a questo DocenteBean
		 */
		public DocenteBean(Docente docente) {
			this.docente = docente;
			
			// Salva i dati iniziali del docente
			this.docenteOld = new Docente(
					docente.getNomeUtente(),
					docente.getEmail(),
					docente.getNome(),
					docente.getCognome(),
					docente.getPassword(),
					docente.getSsd(),
					docente.getQualifica());
			
			// Carica le richieste e la registrazione
			try {
				setRichieste(application.getRichieste(docente));
				
				registrazioneDocente = application.getRegistrazione(docente.getNomeUtente());
			} catch (ApplicationException e) {
				RichiestaRegistrazioneDocente[] vuoto = {};
				setRichieste(vuoto);
			}
		}
		
		/* -----------------------------------
		 * Getters e setters per le proprieta'
		 * ----------------------------------- */
		
		/**
		 * @return il docente incapsulato da questo oggetto.
		 */
		public Docente getDocente() {
			return docente;
		}
		
		/**
		 * @return lo stato di attività di questo docente sottoforma di stringa contenente "si" o "no".
		 */
		public String getAttivo() {
			if (registrazioneDocente.isAttiva())
				return "si";
			
			return "no";
		}
		
		/**
		 * Imposta lo stato di attivita' di questo docente.
		 * 
		 * @param attivo una stringa contenente "si" o "no".
		 */
		public void setAttivo(String attivo) {			
			if (attivo.equals("si"))
				registrazioneDocente.setAttiva(true);
			else if (attivo.equals("no"))
				registrazioneDocente.setAttiva(false);
		}

		/**
		 * Imposta l'elenco delle richieste del docente.<br>
		 * Incapsula ogni richiesta, rappresentata da un'istanza di {@link RichiestaDocente} in
		 * un'istanza di {@link RichiestaBean}.
		 * 
		 * @param richieste l'elenco delle richieste.
		 */
		private void setRichieste(RichiestaRegistrazioneDocente[] richieste) {
			try {
				this.richieste = new RichiestaBean[richieste.length];
				for (int i = 0; i < richieste.length; ++i)
					this.richieste[i] = new RichiestaBean(richieste[i].getRichiesta());
			} catch (ApplicationException e) {
				
			}			
		}
		
		/**
		 * @return {@code true} se questo docente è in fase di eliminazione, {@code false} altrimenti.
		 */
		public boolean getInEliminazione() {
			return inEliminazione;
		}
		
		/* --------------------------------
		 * Metodi per l'estrazione dei dati
		 * -------------------------------- */

		/**
		 * @return un array di {@link RichiestaBean} con l'elenco delle richieste effettuate da questo docente.
		 */
		public RichiestaBean[] getRichieste() {
			return richieste;
		}
		
		/**
		 * @return il numero delle richieste effettuate da questo docente.
		 */
		public int getNumeroRichieste() {
			return richieste.length;
		}
		
		/* ---------------------
		 * Metodi di navigazione
		 * --------------------- */
		
		/**
		 * Imposta questo docente come docenteInDettaglio e va alla pagina di dettaglio docente.
		 * 
		 * @return "/pages/segretario-docente-dettaglio".
		 */
		public String vedi() {
			docenteInDettaglio = this;
			
			return "/pages/segretario-docente-dettaglio";
		}
		
		/**
		 * Aggiorna i dati del docente nel database.<br>
		 * Questo metodo apporta modifiche alla base di dati solamente se rileva un'effettivo cambiamento dei dati
		 * del docente.
		 * Questo metodo utilizza le seguenti proprieta' di presentation.ini:
		 * <ul>
		 *   <li><b>msgDatiModifica</b>: il messaggio visualizzato quando la modifica riesce.</li>
		 *   <li><b>msgErroreModificaDati</b>: il messaggio visualizzato quando la modifica fallisce.</li>
		 * </ul>
		 */
		public void aggiornaDati() {
			try {
				// Trimma i dati
				docente.setCognome(docente.getCognome().trim());
				docente.setEmail(docente.getEmail().trim());
				docente.setNome(docente.getNome().trim());
				docente.setSsd(docente.getSsd().trim());
				docente.setQualifica(docente.getQualifica().trim());
				
				// Modifica effettivamente i dati del docente solo se c'è stato qualche cambiamento
				if (!docente.getNome().equals(docenteOld.getNome()) || !docente.getCognome().equals(docenteOld.getCognome()) ||
						!docente.getEmail().equals(docenteOld.getEmail()) || !docente.getSsd().equals(docenteOld.getSsd()) ||
						!docente.getQualifica().equals(docenteOld.getQualifica()))
					application.aggiornaDocente(docente);
				
				application.impostaStatoAttivazione(registrazioneDocente, registrazioneDocente.isAttiva());
				
				addInfoMessage(getSettings().getProperty("msgDocenteDatiModifica"));
			} catch (ApplicationException e) {
				addWarnMessage(getSettings().getProperty("msgErroreDocenteModificaDati"));
			}
		}
		
		/**
		 * Crea un nuovo docente a partire dai dati memorizzati dalla proprieta' docente di questo oggetto.
		 * Questo metodo utilizza le seguenti proprieta' di presentation.ini:
		 * <ul>
		 *   <li><b>msgDocenteCreato</b>: il messaggio visualizzato quando la creazione riesce.</li>
		 *   <li><b>msgErroreDocentePresente</b>: il messaggio visualizzato quando si tenta di creare un docente
		 *   gia' registrato ai servizi web della facolta'.</li>
		 *   <li><b>msgErroreDocenteRegistrato</b>: il messaggio visualizzato quando si tenta di creare un docente
		 *   che non ha un accounte dei servizi web della facolta' ma che ha una registrazione nel database di BiPoD.</li>
		 *   <li><b>msgErroreCreazioneDocente</b>: il messaggio visualizzato quando la creazione fallisce per un motivo sconosciuto.</li>
		 * </ul>
		 */
		public String creaDocente() {
			try {
				application.nuovoDocente(docente);
				
				// Ricarica la lista dei docenti
				caricaDocenti();
				
				addInfoMessage(getSettings().getProperty("msgDocenteCreato"));
				
				return "/pages/segretario-docenti";
			} catch (StatoDocenteException e) {
				switch (e.getStatoDocente()) {
				case StatoDocenteException.PRESENTE:
					addWarnMessage(getSettings().getProperty("msgErroreDocentePresente"));
					break;
				case StatoDocenteException.REGISTRATO:
					addWarnMessage(getSettings().getProperty("msgErroreDocenteRegistrato"));
				}
				
				return null;
			} catch (ApplicationException e) {
				addWarnMessage(getSettings().getProperty("msgErroreCreazioneDocente"));
				
				return null;
			}
		}
		
		public void iniziaCancellazione() {
			this.inEliminazione = true;
		}
		
		public void annullaCancellazione() {
			this.inEliminazione = false;
		}
		
		public String confermaCancellazione() {
			try {
				if (inEliminazione)
					application.cancellaDocente(docente);
				
				addInfoMessage(getSettings().getProperty("msgCancellazioneDocenteRiuscita").replaceAll("<0>",
						docente.getCognome() + " " + docente.getNome()));
				
				caricaDocenti();
				
				return "/pages/segretario-docenti";
			} catch (ApplicationException e) {
				addWarnMessage(getSettings().getProperty("msgErroreCancellazioneDocente"));
				this.inEliminazione = false;
				
				return null;
			}
		}
	}
	
	/**
	 * RichiestaBean incapsula una richiesta di un docente permettendo di accedere rapidamente anche
	 * ai dati dell'insegnamento a cui la richiesta si riferisce.
	 * 
	 * @author Lorenzo Porzi
	 *
	 */
	public class RichiestaBean {
		private Richiesta richiesta; // La richiesta incapsulata
		private InsegnamentoCorso insegnamento; // L'insegnamento a cui si riferisce la richiesta
		
		/**
		 * Costruisce una RichiestaBean associata ad una Richiesta.
		 * 
		 * @param richiesta la Richiesta da associare a questa RichiestaBean
		 * @throws ApplicationException
		 */
		public RichiestaBean(Richiesta richiesta) throws ApplicationException {
			this.richiesta = richiesta;
			this.insegnamento = application.getInsegnamento(richiesta);
		}
		
		/* ----------------------------------
		 * Setters e getters per le proprietà
		 * ---------------------------------- */
		
		public InsegnamentoCorso getInsegnamento() {
			return insegnamento;
		}
		
		public Richiesta getRichiesta() {
			return richiesta;
		}
		
		public String getDataRichiesta() {
			Format dateFormat = new SimpleDateFormat("dd/MM/yyyy");
			Format timeFormat = new SimpleDateFormat("HH.mm");
			
			String data = dateFormat.format(richiesta.getDataRichiesta());
			data += " alle ";
			data += timeFormat.format(richiesta.getDataRichiesta());
			
			return data;
		}
	}
}
